package com.hqd.ch03.v36.web.servlet.view;

import com.hqd.ch03.v36.utils.StringUtils;
import com.hqd.ch03.v36.web.utils.WebUtils;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

public class InternalResourceView extends AbstractUrlBasedView {

    private boolean alwaysInclude = false;

    private boolean preventDispatchLoop = false;


    public InternalResourceView() {
    }

    public InternalResourceView(String url) {
        super(url);
    }

    public InternalResourceView(String url, boolean alwaysInclude) {
        super(url);
        this.alwaysInclude = alwaysInclude;
    }


    public void setAlwaysInclude(boolean alwaysInclude) {
        this.alwaysInclude = alwaysInclude;
    }

    public void setPreventDispatchLoop(boolean preventDispatchLoop) {
        this.preventDispatchLoop = preventDispatchLoop;
    }

    protected boolean isContextRequired() {
        return false;
    }


    @Override
    protected void renderMergedOutputModel(
            Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

        /**
         * 设置model属性到attribute中
         */
        exposeModelAsRequestAttributes(model, request);

        /**
         * 公开内部属性
         */
        exposeHelpers(request);

        String dispatcherPath = prepareForRendering(request, response);

        /**
         * 获取分发器
         */
        RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
        if (rd == null) {
            throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
                    "]: Check that the corresponding file exists within your web application archive!");
        }
        /**
         * 是否是include属性
         */
        if (useInclude(request, response)) {
            response.setContentType(getContentType());
            rd.include(request, response);
        } else {
            rd.forward(request, response);
        }
    }

    protected void exposeHelpers(HttpServletRequest request) throws Exception {
    }

    protected void exposeModelAsRequestAttributes(Map<String, Object> model,
                                                  HttpServletRequest request) throws Exception {

        model.forEach((name, value) -> {
            if (value != null) {
                request.setAttribute(name, value);
            } else {
                request.removeAttribute(name);
            }
        });
    }

    protected String prepareForRendering(HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        String path = getUrl();

        if (this.preventDispatchLoop) {
            String uri = request.getRequestURI();
            if (path.startsWith("/") ? uri.equals(path) : uri.equals(StringUtils.applyRelativePath(uri, path))) {
                throw new ServletException("Circular view path [" + path + "]: would dispatch back " +
                        "to the current handler URL [" + uri + "] again. Check your ViewResolver setup! " +
                        "(Hint: This may be the result of an unspecified view, due to default view name generation.)");
            }
        }
        return path;
    }

    protected RequestDispatcher getRequestDispatcher(HttpServletRequest request, String path) {
        return request.getRequestDispatcher(path);
    }

    protected boolean useInclude(HttpServletRequest request, HttpServletResponse response) {
        return (this.alwaysInclude || WebUtils.isIncludeRequest(request) || response.isCommitted());
    }

}

